package demo.impl;

import java.lang.reflect.Array;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.springframework.core.MethodParameter;

import com.onlyxiahui.framework.action.dispatcher.ActionContext;
import com.onlyxiahui.framework.action.dispatcher.extend.ActionRequest;
import com.onlyxiahui.framework.action.dispatcher.extend.ActionResponse;
import com.onlyxiahui.framework.action.dispatcher.extend.ArgumentBox;
import com.onlyxiahui.framework.action.dispatcher.extend.MethodArgumentResolver;

import demo.user.bean.User;

/**
 * Date 2019-01-12 21:58:45<br>
 * Description
 * 
 * @author XiaHui<br>
 * @since 1.0.0
 */

public class ServiceArgumentResolver implements MethodArgumentResolver {

	List<Class<?>> list = new ArrayList<>();

	public ServiceArgumentResolver() {
		list.add(User.class);
		list.add(String.class);
	}

	@Override
	public boolean supportsParameter(MethodParameter parameter) {
		boolean support = false;
		Class<?> clazz = parameter.getParameterType();
		support = list.contains(clazz);
		return support;
	}

	@Override
	public Object resolveArgument(ActionContext actionContext, MethodParameter parameter, ActionRequest request, ActionResponse response, ArgumentBox argumentBox) {
		Object object = null;
		// Type t = parameter.getGenericParameterType();

		Object data = request.getData();
		Class<?> clazz = parameter.getParameterType();

		if (clazz.isInstance(data)) {
			object = data;
		}

		if (null == object) {
			object = argumentBox.get(clazz);
		}

		if (null == object && isCanInstance(clazz)) {
			try {
				object = clazz.newInstance();
			} catch (InstantiationException | IllegalAccessException e) {
				e.printStackTrace();
			}
		}
		if (null == object) {
			object = getDefaultValue(clazz);
		}
		return object;
	}

	/**
	 * 
	 * Date 2019-01-06 14:53:42<br>
	 * Description 是否可以被实例化
	 * 
	 * @author XiaHui<br>
	 * @param classType
	 * @return
	 * @since 1.0.0
	 */
	private boolean isCanInstance(Class<?> classType) {
		boolean isAbstract = Modifier.isAbstract(classType.getModifiers());
		boolean can = true;
		if (classType.isAnnotation()) {
			can = false;
		} else if (classType.isArray()) {
			can = false;
		} else if (classType.isEnum()) {
			can = false;
		} else if (classType.isInterface()) {
			can = false;
		} else if (isAbstract) {
			can = false;
		}
		return can;
	}

	/**
	 * 
	 * Date 2019-01-06 14:53:28<br>
	 * Description
	 * 
	 * @author XiaHui<br>
	 * @param clazz
	 * @return
	 * @since 1.0.0
	 */
	@SuppressWarnings("unchecked")
	public <T> T getDefaultValue(Class<T> clazz) {
		Object object = null;
		if (List.class.isAssignableFrom(clazz)) {
			object = new ArrayList<Object>(0);
		} else if (Map.class.isAssignableFrom(clazz)) {
			object = new HashMap<Object, Object>(0);
		} else if (Set.class.isAssignableFrom(clazz)) {
			object = new HashSet<Object>(0);
		} else if (clazz.isArray()) {
			Class<?> componentType = clazz.getComponentType();
			object = Array.newInstance(componentType, 0);
		} else if (clazz == int.class) {
			object = 0;
		} else if (clazz == long.class) {
			object = 0L;
		} else if (clazz == float.class) {
			object = 0.0F;
		} else if (clazz == double.class) {
			object = 0.00D;
		} else if (clazz == byte.class) {
			object = (byte) 0;
		} else if (clazz == char.class) {
			object = '\u0000';
		} else if (clazz == short.class) {
			object = 0;
		} else if (clazz == boolean.class) {
			object = false;
		}
		return ((T) object);
	}
}
